/**
 * Copyright (c) 2007/2008 by Rowan Rodrik van der Molen
 *
 * This file is part of readline-trainer.
 *
 * readline-trainer is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * at your option) any later version.
 *
 * readline-trainer is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with readline-trainer.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <readline/history.h>
#include <readline/readline.h>
#include <libxml/parser.h>
#include <libxml/xpath.h>
#include <regex.h>
#include <wchar.h>
#include <ctype.h>

#include "readline-trainer.h"
#include "parser.h"
#include "lessons.h"


char*
trrl_readline(int);


trrl_lesson_ptr
trrl_get_lesson(trrl_lesson_ptr first_lesson, int lesson_nr)
{
    trrl_lesson_ptr lesson_ptr;
    int index;

    for ( lesson_ptr = first_lesson, index = 1;
          lesson_ptr != NULL && index < lesson_nr;
          lesson_ptr = lesson_ptr->next_lesson, index++
        );

    return lesson_ptr;
}


/**
 * Display a hint for the current exercise.
 */
void
trrl_print_hint(trrl_exercise_ptr exercise)
{
    printf("%s\n", exercise->hint);
}


/**
 * Display all available commands and usage.
 */
void
trrl_print_help()
{
    printf("\e[1;29mlessons\e[m\t\t\tList all available lessons.\n\e[1;29mlesson \e[1;31m[n]\e[m\t\tPractice a particular lesson.\n\e[1;29mhelp\e[m\t\t\tShow this help. (Duh!)\n\e[1;29mquit\e[m\t\t\tQuit this \e[1;30m1337\e[m program.\n");
}


/**
 * Display a list of available lessons with descriptions.
 */
void
trrl_print_lessons(trrl_lesson_ptr first_lesson)
{
    trrl_lesson_ptr lesson_ptr;

    if (first_lesson == NULL)
    {
        printf("There are no lessons.\n");
        return;
    }

    for (lesson_ptr = first_lesson; lesson_ptr != NULL; lesson_ptr = lesson_ptr->next_lesson)
    {
        printf("\e[1;29mlesson %d\e[m\t", lesson_ptr->number);

            if ( lesson_ptr->title == NULL )
            {
                fprintf(stderr, "No title was set for lesson %d!\n", lesson_ptr->number);
                exit(EXIT_FAILURE);
            }

            printf("%s\n", lesson_ptr->title);

    }
}


void
trrl_print_tutor(xmlDocPtr doc, xmlNodePtr node)
{
    xmlNodePtr child_node;

    child_node = node->children;

    while (child_node != NULL)
    {
        if ( 0 == xmlStrcmp(child_node->name,  (const xmlChar *)"br") )
        {
            printf("\n");
        }
        else if ( child_node->type == XML_TEXT_NODE )
        {
            printf("\e[m%s", child_node->content);
        }

        child_node = child_node->next;
    }

    printf("\n");
}


int
trrl_do_exercise(trrl_lesson_ptr lesson1, trrl_lesson_ptr lesson, trrl_exercise_ptr exercise)
{
    char* expected_line;
    char* line;
    int jump_to_lesson_nr = 0;

    expected_line = exercise->line;

    printf("%s\n\n", exercise->instruction);

    while(1)
    {
        line = trrl_readline(lesson->number);

        jump_to_lesson_nr = trrl_global_commands_handler(lesson1, line, lesson->number);

        // Change lesson?
        if (jump_to_lesson_nr && lesson->number != jump_to_lesson_nr)
        {
            break;
        }
        else
        {
            if ( 0 == strcmp(line, expected_line) )
            {
                break;
            }
            else if ( 0 != strcmp(line, expected_line) )
            {
                trrl_print_hint(exercise);
            }
        }

        free(line);
    }

    if (line != NULL)
        free(line);

    free(expected_line);

    return jump_to_lesson_nr;
}


int
trrl_do_lesson(trrl_lesson_ptr first_lesson, int lesson_nr)
{
    trrl_lesson_ptr lesson;
    trrl_exercise_ptr exercise_ptr;
    int jump_to_lesson = 0;

    lesson = trrl_get_lesson(first_lesson, lesson_nr);

    for (exercise_ptr = lesson->first_exercise; exercise_ptr != NULL; exercise_ptr = exercise_ptr->next_exercise)
    {
        jump_to_lesson = trrl_do_exercise(first_lesson, lesson, exercise_ptr);

        if (jump_to_lesson && jump_to_lesson != lesson_nr)
          return jump_to_lesson;
    }

    return 0;
}


char*
trrl_readline(int lesson_nr)
{
    char* line = NULL;
    char* prompt = NULL;

    if (lesson_nr)
    {
        prompt = malloc( sizeof(TRRL_LESSON_PROMPT) ); // FIXME: Will break on more than 99 lessons
        sprintf(prompt, TRRL_LESSON_PROMPT, lesson_nr);
    }
    else
    {
        prompt = malloc( sizeof(TRRL_PROMPT) );
        strcpy(prompt, TRRL_PROMPT);
    }

    line = readline(prompt);
    add_history(line);

    free(prompt);

    return line;
}


int
trrl_global_commands_handler(trrl_lesson_ptr lesson1, char* line, int lesson_nr)
{
    char new_lesson_nr;

    if ( 0 == strcmp(line, "quit") )
    {
        exit(EXIT_SUCCESS);
    }
    else if ( 0 == strcmp(line, "help") )
    {
        trrl_print_help();
    }
    else if ( 0 == strcmp(line, "lessons") )
    {
        trrl_print_lessons(lesson1);
    }
    else if ( NULL != strstr(line, "lesson ") )
    {
        new_lesson_nr = line[7];

        if ( !isdigit(new_lesson_nr) )
        {
            printf("\e[1;31mInvalid argument for \e[1;29mlesson\e[ command.");
        }
        else
        {
            return (int) atoi(&new_lesson_nr);
        }
    }
    else
    {
        return lesson_nr;
    }

    return 0;
}


int
main()
{
    trrl_lesson_ptr lesson1 = NULL; // The first lesson
    char* line = NULL; // The line that is currently being read
    int jump_to_lesson_nr = 0; // The lesson to do next

    lesson1 = trrl_parse_lessons_file(TRRL_LESSONS_XML_FILE);

    printf(TRRL_WELCOME_MSG);

    while (1)
    {
        if (jump_to_lesson_nr)
        {
            jump_to_lesson_nr = trrl_do_lesson(lesson1, jump_to_lesson_nr);
            continue;
        }

        line = trrl_readline(jump_to_lesson_nr);
        jump_to_lesson_nr = trrl_global_commands_handler(lesson1, line, 0);
        free(line);
    }
}

// vim: set expandtab tabstop=4 shiftwidth=4:
